package staff

import (
	"bytes"
	"context"
	"encoding/base64"
	"fmt"
	"os"
	model "service/model/hr"
	mCache "service/model/hr_cache"
	"service/model/mod"
	"strconv"
	"strings"
	"time"

	gpb "gitee.com/cloudapex/protos/hr/pb"
	gpa "gitee.com/cloudapex/protos/hr_cache/pb"
	"gitee.com/cloudapex/ulern/htp"
	"gitee.com/cloudapex/ulern/util"
	"github.com/360EntSecGroup-Skylar/excelize/v2"
	"github.com/gin-gonic/gin"
)

/*
 * 描述: 批量导入员工结构
 *
 *********************************************************************/
type FileData struct {
	Phone    string  //手机号
	CartId   string  //身份证号
	CartName string  //身份证姓名
	PinId    int64   //招聘人ID
	PostId   int64   //岗位ID
	RoleId   int64   //角色ID
	ShowIds  []int64 //组织架构ID
	At       int64   //入职时间
	WorkId   int64   //工号ID
}

func (this *FileData) parsingFile(fileUrl string) ([]FileData, error) {
	//创建一个集合
	list := make([]FileData, 0)
	// 首先读excel
	xlsx, err := excelize.OpenFile(fileUrl)
	if err != nil {
		return nil, nil
	}
	rows, _ := xlsx.GetRows("Sheet1")
	for i, row := range rows {
		// 去掉第一行，第一行是表头
		if i == 0 || len(row) == 0 {
			continue
		}
		if strings.TrimSpace(row[0]) == "" {
			return list, nil
		}
		if len(row) < 8 {
			return nil, fmt.Errorf("在第%d行字段不完整 发生错误:%v", i+1, err)
		}

		fmt.Println(row)
		var val FileData
		val.Phone = row[0]
		val.CartId = row[1]
		val.CartName = row[2]
		val.PostId, _ = strconv.ParseInt(row[3], 10, 64)
		val.RoleId, _ = strconv.ParseInt(row[4], 10, 64)
		for _, show := range strings.Split(row[5], "，") {
			nShowId, _ := strconv.ParseInt(show, 10, 64)
			val.ShowIds = append(val.ShowIds, nShowId)
		}
		// t, err := util.TimeParse(time.Time{}, row[6])
		// if err != nil {
		// 	return nil, fmt.Errorf("在第%d行, 第%d列 发生错误:%v", i+1, 8, err)
		// }

		val.At = StringToTimeEx(row[6])
		val.WorkId, _ = strconv.ParseInt(row[7], 10, 64)
		list = append(list, val)
	}
	return list, nil
}
func StringToTimeEx(strTime string) int64 {
	//获取本地location
	strTem := "2006-01-02 15:04:05"
	timeLocal, _ := time.LoadLocation("Local")
	theTime, _ := time.ParseInLocation(strTem, strTime, timeLocal)
	return theTime.Unix()
}
func (this *FileData) ParsingErrFile(fileData []FileData) ([]byte, error) {
	var out *bytes.Buffer

	var err error
	xlsxNews := excelize.NewFile()
	xlsxNews.SetSheetRow("Sheet1", "A1", &[]interface{}{
		"手机号", "身份证号", "身份证号姓名", "招聘人", "岗位", "角色", "组织架构", "入职时间",
	})
	if len(fileData) > 0 {
		//因为index是从0开始，第一行被字段占用，从第二行开始写入整行数据
		lint := 2
		for _, v := range fileData {
			sShowId := ""
			for n, id := range v.ShowIds {
				if n >= len(v.ShowIds)-1 {
					sShowId = fmt.Sprintf("%s，%d", sShowId, id)
				}
				sShowId = fmt.Sprintf("%s，%d，", sShowId, id)
			}
			xlsxNews.SetSheetRow("Sheet1", "A"+strconv.Itoa(lint), &[]interface{}{
				v.Phone, v.CartId, v.CartName, v.PinId,
				v.PostId, v.RoleId, sShowId, util.TimeFormat(time.Unix(v.At, 0)),
			})
			lint++
		}
		out, err = xlsxNews.WriteToBuffer()
		return out.Bytes(), err
	}
	return nil, err
}

/*
 * 描述: 批量导入员工合同
 *
 *********************************************************************/
type ContractData struct {
	CartId       string //身份证号
	Status       int64  //是否签署合同
	ContractType int64  //合同类型
	At           int64  //签署时间
}

func (this *ContractData) ParsingFile(fileUrl string) ([]ContractData, error) {
	//创建一个集合
	list := make([]ContractData, 0)
	// 首先读excel
	xlsx, err := excelize.OpenFile(fileUrl)
	if err != nil {
		return nil, nil
	}
	rows, _ := xlsx.GetRows("Sheet1")
	for i, row := range rows {
		// 去掉第一行，第一行是表头
		if i == 0 {
			continue
		}
		var val ContractData
		val.CartId = row[0]
		val.Status, _ = strconv.ParseInt(row[1], 10, 64)
		val.ContractType, _ = strconv.ParseInt(row[2], 10, 64)
		t, err := util.TimeParse(time.Time{}, row[3])
		if err != nil {
			return nil, fmt.Errorf("在第%d行, 第%d列 发生错误:%v", i+1, 4, err)
		}
		val.At = t.Unix()
		list = append(list, val)
	}
	return list, nil
}

/*
 * 描述: 处理错误的数据文件  合同的
 *
 *********************************************************************/
func (this *ContractData) ParsingErrFile(fileData []ContractData) ([]byte, error) {
	var out *bytes.Buffer

	var err error
	xlsxNews := excelize.NewFile()
	xlsxNews.SetSheetRow("Sheet1", "A1", &[]interface{}{
		"身份证号码", "是否签署合同（1未签署 2已签署）", "合同签署类型（1电子 2纸质）", "签订时间",
	})
	if len(fileData) > 0 {
		//因为index是从0开始，第一行被字段占用，从第二行开始写入整行数据
		lint := 2
		for _, v := range fileData {
			xlsxNews.SetSheetRow("Sheet1", "A"+strconv.Itoa(lint), &[]interface{}{
				v.CartId, v.Status, v.ContractType, util.TimeFormat(time.Unix(v.At, 0)),
			})
			lint++
		}
		out, err = xlsxNews.WriteToBuffer()
		return out.Bytes(), err
	}
	return nil, err
}

/*
 * 描述: 批量导入员工社保
 *
 *********************************************************************/
type InsuranceData struct {
	CartId string //身份证号
	Status int64  //是否已交社保
	City   string //缴保城市
	At     int64  //缴保时间
}

func (this *InsuranceData) ParsingFile(fileUrl string) ([]InsuranceData, error) {
	//创建一个集合
	list := make([]InsuranceData, 0)
	// 首先读excel
	xlsx, err := excelize.OpenFile(fileUrl)
	if err != nil {
		return nil, nil
	}
	rows, _ := xlsx.GetRows("Sheet1")
	for i, row := range rows {
		// 去掉第一行，第一行是表头
		if i == 0 {
			continue
		}
		var val InsuranceData
		val.CartId = row[0]
		val.Status, _ = strconv.ParseInt(row[1], 10, 64)
		val.City = row[2]
		t, err := util.TimeParse(time.Time{}, row[3])
		if err != nil {
			return nil, fmt.Errorf("在第%d行, 第%d列 发生错误:%v", i+1, 4, err)
		}
		val.At = t.Unix()
		list = append(list, val)
	}
	return list, nil
}

/*
 * 描述: 处理错误的数据文件  社保的
 *
 *********************************************************************/
func (this *InsuranceData) ParsingErrFile(fileData []InsuranceData) ([]byte, error) {
	var out *bytes.Buffer

	var err error
	xlsxNews := excelize.NewFile()
	xlsxNews.SetSheetRow("Sheet1", "A1", &[]interface{}{
		"身份证号码", "是否已缴社保（1未缴 2已缴）", "缴保城市", "缴保时间",
	})
	if len(fileData) > 0 {
		//因为index是从0开始，第一行被字段占用，从第二行开始写入整行数据
		lint := 2
		for _, v := range fileData {
			xlsxNews.SetSheetRow("Sheet1", "A"+strconv.Itoa(lint), &[]interface{}{
				v.CartId, v.Status, v.City, util.TimeFormat(time.Unix(v.At, 0)),
			})
			lint++
		}
		out, err = xlsxNews.WriteToBuffer()
		return out.Bytes(), err
	}
	return nil, err
}

/*
 * 描述: 导入员工
 * 路由: tool/exportStaff
 * 方法: POST
 *********************************************************************/
type ExportStaff struct {
}

func (this *ExportStaff) Handle(c *gin.Context, ctx context.Context) htp.Response {
	jwtUser := mod.CurrUser(c)
	util.Debug("ExportStaff user:%v", jwtUser)

	file, err := c.FormFile("file")
	if err != nil {
		util.Error("url error:%v", err.Error())
		return htp.RespErr(int(StaffCode_ParameterError), "文件有误", err)
	}
	util.Error("exportStaff :%v", file.Filename)

	impFile := util.ExePathJoin(fmt.Sprintf("upload/%d_%s", time.Now().Unix(), file.Filename))
	util.Error("impFile :%v", impFile)

	os.Remove(impFile)
	if err := c.SaveUploadedFile(file, impFile); err != nil {
		return htp.RespErr(int(StaffCode_ParameterError), "上传失败", err)
	}
	var fileData FileData
	list, err := fileData.parsingFile(impFile)
	fmt.Println(list)

	if err != nil {
		os.Remove(impFile)
		return htp.RespErr(int(StaffCode_ParameterError), "读取文件失败", err)
	}
	errInfo := ""
	if len(list) > 0 {
		errData := make([]FileData, 0)
		for i, v := range list {

			if v.WorkId != 0 {
				rsp_, err_ := mCache.StaffCacheServer.GetStaffCacheByWorkId(ctx, &gpa.HrBaseCacheReq{CId: jwtUser.CId, WorkId: v.WorkId})
				if err_ != nil {
					os.Remove(impFile)
					return htp.RespErr(2, "服务错误", err_)
				}
				if rsp_ != nil && rsp_.Id != 0 {
					errInfo = fmt.Sprintf("第 %d 行数据, 工号=%v 已存在", i+2, v.WorkId)
					errData = append(errData, v)
					continue
				}
			}

			// rsp_, err_ := mCache.StaffCacheServer.GetStaffCacheByNumberId(ctx, &gpa.HrBaseCacheReq{CId: jwtUser.CId, NumberId: v.CartId})
			// if err_ != nil {
			// 	os.Remove(impFile)
			// 	return htp.RespErr(2, "服务错误", err_)
			// }
			// if rsp_ != nil && rsp_.Id != 0 {
			// 	errInfo = fmt.Sprintf("第 %d 行数据, 身份证号=%v 已存在", i+2, v.CartId)
			// 	errData = append(errData, v)
			// 	continue
			// }

			//判断岗位 检查错误的数据
			mOk, err := mCache.PostsCache.GetPostList(ctx, &gpa.PostBaseCacheReq{
				CId: jwtUser.CId,
			}, v.PostId)
			if err != nil {
				os.Remove(impFile)
				return htp.RespErr(2, "服务错误", err)
			}
			fmt.Println("岗位检测", mOk)
			if mOk == false {
				errInfo = fmt.Sprintf("第 %d 行数据, 岗位Id=%d 不存在", i+2, v.PostId)
				errData = append(errData, v)
				continue
			}
			//组织架构检查
			sOk := false
			for _, showId := range v.ShowIds {
				if err == nil {
					sOk, err = mCache.FrameWorkCache.FrameCacheList(ctx, &gpa.FrameworkCacheReq{
						CId: jwtUser.CId,
					}, showId)
				}
				if sOk == false {
					break
				}
			}
			fmt.Println("组织检测", sOk)
			if err != nil {
				os.Remove(impFile)
				return htp.RespErr(2, "服务错误", err)
			}
			if sOk == false {
				errInfo = fmt.Sprintf("第 %d 行数据, 组织架构Id=%v 不存在", i+2, v.ShowIds)
				errData = append(errData, v)
				continue
			}
			//角色检查
			if v.RoleId > 0 {
				rOk, err := mCache.RolesCache.RoleCacheList(ctx, &gpa.RolesBaseCacheReq{
					CId: jwtUser.CId,
				}, v.RoleId)
				fmt.Println("角色检测", rOk)
				if err != nil {
					os.Remove(impFile)
					return htp.RespErr(2, "服务错误", err)
				}
				if rOk == false {
					errInfo = fmt.Sprintf("第 %d 行数据, 角色Id=%d 不存在", i+2, v.RoleId)
					errData = append(errData, v)
					continue
				}
			}
			//批量插入员工
			rsp, rpcErr := model.StaffServer.HrAddUser(ctx, &gpb.HrBaseReq{
				CId:        jwtUser.CId,
				NumberId:   v.CartId,
				NumberName: v.CartName,
				Phone:      v.Phone,
				TWorkId:    0,
				WId:        v.PostId,
				RoleId:     v.RoleId,
				ShowIds:    v.ShowIds,
				CreatAt:    v.At,
				WorkId:     v.WorkId,
			})
			if rpcErr != nil {
				return htp.RespModelErr("", rpcErr)
			}
			fmt.Println(rsp.Status)
			if rsp.Status < 2 {
				//插入合同信息
				contReq := make([]*gpb.BaseUInfo, 0)

				contPara := new(gpb.BaseUInfo)
				contPara.Hid = rsp.Id
				contReq = append(contReq, contPara)
				model.StaffServer.EditContract(ctx, &gpb.StaffContractReq{
					OperId:     jwtUser.UId,
					BaseUInfos: contReq,
					State:      1,
					ContType:   0,
					ContAt:     0,
				})

				//插入社保信息
				socReq := make([]*gpb.BaseUInfo, 0)
				//批量修改多个员工的合同
				socPara := new(gpb.BaseUInfo)
				socPara.Hid = rsp.Id
				socReq = append(socReq, socPara)
				model.StaffServer.EditInsurance(ctx, &gpb.StaffInsuranceReq{
					BaseUInfos: contReq,
					State:      1,
					City:       "",
					At:         0,
					OperId:     jwtUser.UId,
				})
				//添加一条岗位变更记录
				_, err = model.Framework.AddChangeFramRole(ctx, &gpb.ChangeFraRoleReq{
					CId:      jwtUser.CId,
					UId:      rsp.Id,
					OperId:   jwtUser.UId,
					FrameIds: v.ShowIds,
					RoleId:   v.RoleId,
					WId:      v.PostId,
				})
				// 添加进缓存
				mCache.StaffCacheServer.AddStaffCacheInfo(ctx, &gpa.HrBaseCacheReq{
					Id:         rsp.Id,
					CId:        jwtUser.CId,
					NumberId:   v.CartId,
					NumberName: v.CartName,
					Phone:      v.Phone,
					WId:        v.PostId,
					WorkId:     v.WorkId,
					RoleId:     v.RoleId,
					CreatAt:    v.At,
				})
			} else {
				errData = append(errData, v)
			}
		}
		os.Remove(impFile)
		fmt.Println(errData)

		//处理错误的数据
		if len(errData) > 0 {
			var fileData FileData
			fileUrl, err := fileData.ParsingErrFile(errData)
			if err != nil {
				fmt.Println("文件生成有误", err)
				return htp.RespErr(2, "生成数据文件失败", nil)
			}
			if errInfo != "" {
				rsp_ := htp.RespErr(3, errInfo, nil)
				rsp_.Data = fileUrl
				return rsp_
			}

			return htp.RespOK("", base64.StdEncoding.EncodeToString(fileUrl))
		}
	}
	var fileUrl string
	return htp.RespOK("", fileUrl)
}

/*
 * 描述: 导入员工合同
 * 路由: tool/importContract
 * 方法: POST
 *********************************************************************/
type ImportContract struct {
}

func (this *ImportContract) Handle(c *gin.Context, ctx context.Context) htp.Response {
	jwtUser := mod.CurrUser(c)
	file, err := c.FormFile("file")
	if err != nil {
		fmt.Println("url error:", err.Error())
		return htp.RespErr(2, "文件有误", nil)
	}
	impFile := util.ExePathJoin(fmt.Sprintf("upload/%d_%s", time.Now().Unix(), file.Filename))
	util.Debug(impFile)
	if err := c.SaveUploadedFile(file, impFile); err != nil {
		return htp.RespErr(2, "上传失败", err)
	}
	var fileData ContractData
	list, err := fileData.ParsingFile(impFile)
	fmt.Println(list)

	if err != nil {
		os.Remove(impFile)
		return htp.RespErr(2, "读取文件失败", err)
	}
	if len(list) > 0 {
		errData := make([]ContractData, 0)
		//员工列表
		for _, v := range list {
			//检查员工身份证号
			userId, err := mCache.StaffCacheServer.StaffCacheList(ctx, &gpa.HrBaseCacheReq{
				CId: jwtUser.CId,
			}, v.CartId)
			if err != nil {
				os.Remove(impFile)
				return htp.RespErr(2, "服务有误", err)
			}
			fmt.Println("人员检查", userId)
			if userId <= 0 {
				errData = append(errData, v)
				continue
			}
			//插入合同信息
			contReq := make([]*gpb.BaseUInfo, 0)

			contPara := new(gpb.BaseUInfo)
			contPara.Hid = userId
			contReq = append(contReq, contPara)

			model.StaffServer.EditContract(ctx, &gpb.StaffContractReq{
				OperId:     jwtUser.UId,
				BaseUInfos: contReq,
				State:      v.Status,
				ContType:   v.ContractType,
				ContAt:     v.At,
			})

		}
		os.Remove(impFile)
		fmt.Println(errData)
		//处理错误的数据
		if len(errData) > 0 {
			var fileData ContractData
			fileUrl, err := fileData.ParsingErrFile(errData)
			if err != nil {
				fmt.Println("文件生成有误", err)
				return htp.RespErr(2, "生成数据文件失败", nil)
			}
			return htp.RespOK("", base64.StdEncoding.EncodeToString(fileUrl))
		}
	}
	var fileUrl string
	return htp.RespOK("", fileUrl)
}

/*
 * 描述: 导入员工社保
 * 路由: tool/importEducation
 * 方法: POST
 *********************************************************************/
type ImportEducation struct {
}

func (this *ImportEducation) Handle(c *gin.Context, ctx context.Context) htp.Response {
	jwtUser := mod.CurrUser(c)
	file, err := c.FormFile("file")
	if err != nil {
		fmt.Println("url error:", err.Error())
		return htp.RespErr(2, "文件有误", nil)
	}

	impFile := util.ExePathJoin(fmt.Sprintf("upload/%d_%s", time.Now().Unix(), file.Filename))
	util.Debug(impFile)
	if err := c.SaveUploadedFile(file, impFile); err != nil {
		return htp.RespErr(2, "上传失败", err)
	}
	var fileData InsuranceData
	list, err := fileData.ParsingFile(impFile)
	fmt.Println(list)

	if err != nil {
		os.Remove(impFile)
		return htp.RespErr(2, "读取文件失败", err)
	}
	if len(list) > 0 {
		errData := make([]InsuranceData, 0)
		//员工列表
		for _, v := range list {
			//检查员工身份证号
			userId, err := mCache.StaffCacheServer.StaffCacheList(ctx, &gpa.HrBaseCacheReq{
				CId: jwtUser.CId,
			}, v.CartId)
			if err != nil {
				os.Remove(impFile)
				return htp.RespErr(2, "服务有误", err)
			}
			fmt.Println("人员检查", userId)
			if userId <= 0 {
				errData = append(errData, v)
				continue
			}

			//插入社保信息
			socReq := make([]*gpb.BaseUInfo, 0)
			//批量修改多个员工的合同
			socPara := new(gpb.BaseUInfo)
			socPara.Hid = 0
			socReq = append(socReq, socPara)
			model.StaffServer.EditInsurance(ctx, &gpb.StaffInsuranceReq{
				BaseUInfos: socReq,
				State:      v.Status,
				City:       v.City,
				At:         v.At,
				OperId:     jwtUser.UId,
			})

		}
		os.Remove(impFile)
		fmt.Println(errData)
		//处理错误的数据
		if len(errData) > 0 {
			var fileData InsuranceData
			fileUrl, err := fileData.ParsingErrFile(errData)
			if err != nil {
				fmt.Println("文件生成有误", err)
				return htp.RespErr(2, "生成数据文件失败", nil)
			}
			return htp.RespOK("", base64.StdEncoding.EncodeToString(fileUrl))
		}
	}
	var fileUrl string
	return htp.RespOK("", fileUrl)
}
